(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
;; at table edges
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 4) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 4)
  )
 )
)
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 0) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 0)
  )
 )
)
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 0) $foo $foo $foo $foo $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 2)
  )
 )
)
;; imported table
(module
 (type $ii (func (param i32 i32)))
 (import "env" "table" (table $table 5 5 funcref))
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
;; exported table
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (export "tab" (table $0))
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
;; non-constant table offset
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (global $g (mut i32) (i32.const 1))
 (elem (global.get $g) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
;; non-constant call index
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32) (param $z i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (local.get $z)
  )
 )
)
;; bad index
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 5)
  )
 )
)
;; missing index
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 2)
  )
 )
)
;; bad type
(module
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
;; no table
(module
 (func $foo (param i32)
  (unreachable)
 )
)
;; change types
(module
 (type (func))
 (table $0 8 8 funcref)
 (func $0
  (block ;; the type of this block will change
   (nop)
   (call_indirect (type 0)
    (i32.const 15)
   )
  )
 )
)
(module ;; indirect tail call
 (type $ii (func (param i32 i32)))
 (table $0 5 5 funcref)
 (elem (i32.const 1) $foo)
 (func $foo (param i32) (param i32)
  (unreachable)
 )
 (func $bar (param $x i32) (param $y i32)
  (return_call_indirect (type $ii)
   (local.get $x)
   (local.get $y)
   (i32.const 1)
  )
 )
)
